#pragma once

#include "../Common/Net.hpp"
#include "../Common/Dispatcher.hpp"
#include "../Common/Message.hpp"
#include <unordered_set>

namespace zgwrpc
{
    namespace server
    {
        // 服务端主题订阅管理
        class TopicManager
        {
        public:
            using ptr = std::shared_ptr<TopicManager>;
            TopicManager(){}

            void OnTopicMessage(BaseConnection::ptr conn, const TopicRequest::ptr &req) // 主题消息处理
            {
                // 1.添加主题 2.删除主题 3.发布消息 4.订阅主题 5.取消订阅
                TopicOpType op = req->topicOpType();
                bool ret = true;
                switch (op)
                {
                    // 添加主题
                case TopicOpType::TOPIC_CREATE:
                    AddTopic(conn, req);
                    break;
                    // 删除主题
                case TopicOpType::TOPIC_REMOVE:
                    RemoveTopic(conn, req);
                    break;
                    // 添加订阅
                case TopicOpType::TOPIC_SUBSCRIBE:
                    ret = SubscribeTopic(conn, req);
                    break;
                    // 取消订阅
                case TopicOpType::TOPIC_CANCEL:
                    ret = RemoveSub(conn, req);
                    break;
                    // 发布消息
                case TopicOpType::TOPIC_PUBLISH:
                    ret = PublishMessage(conn, req);
                    break;
                default:
                    ret = false;
                    return OnTopicErrorResponse(conn, req, RCode::RCODE_INVALID_OPTYPE);
                    break;
                }
                if (!ret)
                    return OnTopicErrorResponse(conn, req, RCode::RCODE_NOT_FOUND_TOPIC);
                return OnTopicResponse(conn, req);
            }
            void OnTopicErrorResponse(const BaseConnection::ptr &conn, const TopicRequest::ptr &msg, RCode rcode)
            {
                auto msg_rsp = MessageFactory::create<TopicResponse>();
                msg_rsp->setId(msg->rid());
                msg_rsp->setMType(MType::RSP_TOPIC);
                msg_rsp->setRCode(rcode);
                msg_rsp->setTopicOpType(msg->topicOpType());
                conn->send(msg_rsp);
            }

            // 断开连接时处理逻辑
            void OnShutdown(const BaseConnection::ptr &conn)
            {
                // std::unordered_map<std::string, Topic::ptr> _topics;                     // 主题名称与主题的映射关系
                // std::unordered_map<BaseConnection::ptr, SubDescrebe::ptr> _sub_descrebe; // 订阅者与订阅主题的描述关系
                std::vector<Topic::ptr> topics;
                SubDescrebe::ptr sub;
                {
                    unique_lock<mutex> lock(_mutex);
                    auto it = _sub_descrebe.find(conn);
                    if (it == _sub_descrebe.end())
                        return;
                    // 1. 查找相关联的主题对象
                    sub = it->second;

                    for (auto &topic_name : it->second->topics)
                    {
                        auto it_topic = _topics.find(topic_name);
                        if (it_topic != _topics.end())
                            topics.push_back(it_topic->second);
                    }
                    _sub_descrebe.erase(it);
                }
                // 删除主题下的订阅者
                for (auto &topic : topics)
                {
                    topic->RemoveSub(sub);
                }
            }

            void OnTopicResponse(const BaseConnection::ptr &conn, const TopicRequest::ptr &msg)
            {
                auto msg_rsp = MessageFactory::create<TopicResponse>();
                msg_rsp->setId(msg->rid());
                msg_rsp->setMType(MType::RSP_TOPIC);
                msg_rsp->setRCode(RCode::RCODE_OK);
                msg_rsp->setTopicOpType(msg->topicOpType());
                conn->send(msg_rsp);
            }

            void AddTopic(BaseConnection::ptr conn, const TopicRequest::ptr &req)
            {
                // 添加主题
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _topics.find(req->topicKey());
                if (it == _topics.end())
                {
                    // 如果没有该主题，则创建该主题
                    Topic::ptr topic = make_shared<Topic>(req->topicKey());
                    _topics.insert(std::make_pair(req->topicKey(), topic));
                }
            }

            // 删除一个主题
            void RemoveTopic(BaseConnection::ptr conn, const TopicRequest::ptr &req)
            {
                string topic_name = req->topicKey();
                // std::unordered_map<std::string, Topic::ptr> _topics;                     // 主题名称与主题的映射关系
                // std::unordered_map<BaseConnection::ptr, SubDescrebe::ptr> _sub_descrebe; // 订阅者与订阅主题的描述关系
                // 删除里边的资源
                Topic::ptr topic;
                SubDescrebe::ptr sub_descrebe;
                // 订阅者集合  该主题下的订阅者
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _topics.find(topic_name); // 产看是否存在该主题
                    if (it == _topics.end())
                        return;

                    topic = it->second;

                    for (auto &sub : topic->subs) // 便利该主题下的连接
                    {
                        sub->RemoveTopic(topic_name); // 订阅者删除主题
                    }
                    _topics.erase(it); // 删除主题
                }
            }

            // 添加订阅
            bool SubscribeTopic(BaseConnection::ptr conn, const TopicRequest::ptr &req)
            {
                Topic::ptr topic;
                SubDescrebe::ptr sub_descrebe;
                {
                    unique_lock<mutex> lock(_mutex);
                    auto it = _topics.find(req->topicKey());
                    if (it == _topics.end())
                    {
                        LOG(LogLevel::ERROR) << "没有该主题";
                        return false;
                    }
                    topic = it->second;

                    // 查找描述
                    auto it_sub = _sub_descrebe.find(conn);
                    if (it_sub != _sub_descrebe.end())
                    {
                        sub_descrebe = it_sub->second;
                    }
                    else // 如果没有该描述，则创建该描述
                    {
                        sub_descrebe = make_shared<SubDescrebe>(conn);
                        _sub_descrebe.insert(std::make_pair(conn, sub_descrebe));
                    }
                }
                topic->AddSub(sub_descrebe);             // 主题添加订阅者
                sub_descrebe->AddTopic(req->topicKey()); // 描述添加主题
                return true;
            }

            // 取消订阅
            bool RemoveSub(BaseConnection::ptr conn, const TopicRequest::ptr &req)
            {
                // std::unordered_map<std::string, Topic::ptr> _topics;                     // 主题名称与主题的映射关系
                // std::unordered_map<BaseConnection::ptr, SubDescrebe::ptr> _sub_descrebe; // 订阅者与订阅主题的描述关系
                // 删除里边的资源
                std::string topic_name = req->topicKey();
                Topic::ptr topic;
                SubDescrebe::ptr sub_descrebe;
                {
                    auto it = _topics.find(topic_name);
                    if (it == _topics.end())
                    {
                        LOG(LogLevel::ERROR) << "没有该主题";
                        return false;
                    }
                    topic = it->second;
                    // 查找描述
                    auto it_sub = _sub_descrebe.find(conn);
                    if (it_sub != _sub_descrebe.end())
                    {
                        sub_descrebe = it_sub->second;
                    }
                    else
                    {
                        return false;
                    }
                }
                sub_descrebe->RemoveTopic(topic_name);
                topic->RemoveSub(sub_descrebe);
                return true;
            }

            bool PublishMessage(BaseConnection::ptr conn, const TopicRequest::ptr &req)
            {
                // 发布消息
                Topic::ptr topic;
                {
                    auto it = _topics.find(req->topicKey());
                    if (it == _topics.end())
                    {
                        LOG(LogLevel::ERROR) << "没有该主题";
                        return false;
                    }
                    topic = it->second;
                }
                topic->PublishMessage(req); // 发布消息
                return true;
            }

            struct SubDescrebe // 对一个订阅者的关联主题描述
            {
                using ptr = std::shared_ptr<SubDescrebe>;
                std::mutex _mutex;
                BaseConnection::ptr conn;               // 连接指针
                std::unordered_set<std::string> topics; // 订阅者不止订阅了一个主题
                SubDescrebe(const BaseConnection::ptr &conn) : conn(conn)
                {
                }
                void AddTopic(const std::string &topic)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    topics.insert(topic);
                }
                void RemoveTopic(const std::string &topic)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    topics.erase(topic);
                }
            };

            struct Topic
            {
                using ptr = std::shared_ptr<Topic>;
                std::mutex _mutex;
                std::string topic_name; // 用于保存订阅主题关联的连接
                std::unordered_set<SubDescrebe::ptr> subs;
                Topic(const std::string &name) : topic_name(name)
                {
                }
                // 创建连接时回调
                void AddSub(const SubDescrebe::ptr &sub)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    subs.insert(sub);
                }
                // 断开连接时回调
                void RemoveSub(const SubDescrebe::ptr &sub)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    subs.erase(sub);
                }
                // 发布消息
                void PublishMessage(const BaseMessage::ptr &msg) // 主题的发布
                {
                    for (auto &sub : subs)
                    {
                        sub->conn->send(msg);
                    }
                }
            };

        private:
            // 主题操作 -> 1.添加主题 2.删除主题 3.发布消息 4.订阅主题 5.取消订阅
            std::mutex _mutex;
            std::unordered_map<std::string, Topic::ptr> _topics;                     // 主题名称与主题的映射关系
            std::unordered_map<BaseConnection::ptr, SubDescrebe::ptr> _sub_descrebe; // 订阅者与订阅主题的描述关系
        };
    }
}